package com.piaoniu.pngen.convert;

import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.piaoniu.pngen.model.Column;
import com.piaoniu.pngen.model.Table;

import java.util.HashMap;
import java.util.Map;

/**
 * @author code4crafter@gmail.com
 * Date: 16/7/28
 * Time: 下午5:30
 */
public class Class2TableConverter {

	private static final String DEFAULT_TYPE = "varchar(512)";

	private static Map<PsiPrimitiveType, String> primitiveTypeMap = new HashMap<>();

	private static Map<String, String> referenceTypeMap = new HashMap<>();

	static {
		primitiveTypeMap.put(PsiType.BOOLEAN, "tinyint");
		primitiveTypeMap.put(PsiType.BYTE, "smallint");
		primitiveTypeMap.put(PsiType.CHAR, "smallint");
		primitiveTypeMap.put(PsiType.DOUBLE, "double");
		primitiveTypeMap.put(PsiType.FLOAT, "float");
		primitiveTypeMap.put(PsiType.SHORT, "smallint");
		primitiveTypeMap.put(PsiType.INT, "int");
		primitiveTypeMap.put(PsiType.LONG, "bigint");

		referenceTypeMap.put("java.lang.Integer", "int(11)");
		referenceTypeMap.put("java.lang.String", "varchar(255)");
		referenceTypeMap.put("java.lang.Long", "bigint(20)");
		referenceTypeMap.put("java.lang.Float", "float(10,2)");
		referenceTypeMap.put("java.lang.Double", "double(10,2)");
		referenceTypeMap.put("java.lang.Character", "char(255)");
		referenceTypeMap.put("java.lang.Boolean", "tinyint(1)");
		referenceTypeMap.put("java.lang.Byte", "smallint");
		referenceTypeMap.put("java.lang.Short", "smallint");
		referenceTypeMap.put("Bigdecimal", "decimal(10,2)");
		referenceTypeMap.put("Date", "datetime");
	}

	public Table convert(PsiClass psiClass) {
		Table table = new Table();
		table.setName(underScoreName(psiClass.getName()));
		for (PsiField psiField : psiClass.getFields()) {
			if (psiField.getModifierList().hasExplicitModifier("static")) {
				continue;
			}

			Column column = new Column();
			if (psiField.getDocComment() != null) {
				StringBuilder commentAccum = new StringBuilder();
				for (PsiElement psiElement : psiField.getDocComment().getDescriptionElements()) {
					commentAccum.append(psiElement.getText());
				}
				column.setComment(commentAccum.toString().replaceAll("\\n+", "").trim());
			}
			column.setName(underScoreName(psiField.getName()));
			if (psiField.getType() instanceof PsiPrimitiveType) {
				column.setType(primitiveTypeMap.get(psiField.getType()));
			} else if (psiField.getType() instanceof PsiClassReferenceType) {
				column.setType(referenceTypeMap.get((psiField.getType().getCanonicalText())));
			}
			if (column.getType() == null) {
				column.setType(DEFAULT_TYPE);
			}
			table.getColumns().add(column);
		}
		return table;
	}

	private String underScoreName(String name) {
		StringBuilder result = new StringBuilder();
		if ((name != null) && (name.length() > 0)) {
			result.append(name.substring(0, 1).toLowerCase());
			for (int i = 1; i < name.length(); ++i) {
				String s = name.substring(i, i + 1);
				if (s.equals(s.toUpperCase())) {
					result.append("_");
					result.append(s.toLowerCase());
				} else {
					result.append(s);
				}
			}
		}
		return result.toString();
	}
}
